package com.partsoft.dits.log;

import java.lang.reflect.Method;

import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import com.partsoft.dits.DataChangeLog;
import com.partsoft.dits.DataEdgeDescriptor;
import com.partsoft.dits.dsm.AbstractDataSourceResolveBean;
import com.partsoft.dits.log.ChangeLogResolver;
import com.partsoft.dits.log.ContextJdbcDataChangeLogStorage;

public class AbstractDataSoruceEdgeChangeLogResolveBean extends AbstractDataSourceResolveBean {

	private ContextJdbcDataChangeLogStorage changeLogResolver;

	private String changeLogNamespace;

	private String changeLogTableSchema = "AAA";

	private String changeLogTableName = "DATA_CHANGE_LOG_HISTORY";

	private String changeLogCreateStorageJdbcSQLTemplate = ContextJdbcDataChangeLogStorage.Default_CreateStorageJdbcSQL_Template;

	private String changeLogSaveLogJdbcSQLTemplate = ContextJdbcDataChangeLogStorage.Default_SaveLogJdbcSQL_Template;

	private String changeLogLastLogJdbcSQLTemplate = ContextJdbcDataChangeLogStorage.Default_GetLastLogJdbcSQL_Template;

	private String changeLogLastChangeLogIdSQLTemplate = ContextJdbcDataChangeLogStorage.Default_GetLastChangeLogIdSQL_Template;

	private String changeLogIdEQChangeLogSQLTemplate = ContextJdbcDataChangeLogStorage.Default_GetIdEQChangeLogSQL_Template;

	private String changeLogIdGtChangeLogSQLTemplate = ContextJdbcDataChangeLogStorage.Default_GetIdGtChangeLogSQL_Template;

	private Class<?> descriptorClass;

	private String descriptorIdentity;

	private DataEdgeDescriptor changeLogDataDescriptor = null;

	public void setDescriptorIdentity(String descriptorIdentity) {
		this.descriptorIdentity = descriptorIdentity;
	}

	public String getDescriptorIdentity() {
		return descriptorIdentity;
	}

	public void setDescriptorClass(Class<?> descriptorClass) {
		this.descriptorClass = descriptorClass;
	}

	public Class<?> getDescriptorClass() {
		return descriptorClass;
	}

	public String getChangeLogCreateStorageJdbcSQLTemplate() {
		return changeLogCreateStorageJdbcSQLTemplate;
	}

	public void setChangeLogCreateStorageJdbcSQLTemplate(String changeLogCreateStorageJdbcSQLTemplate) {
		this.changeLogCreateStorageJdbcSQLTemplate = changeLogCreateStorageJdbcSQLTemplate;
	}

	public String getChangeLogSaveLogJdbcSQLTemplate() {
		return changeLogSaveLogJdbcSQLTemplate;
	}

	public void setChangeLogSaveLogJdbcSQLTemplate(String changeLogSaveLogJdbcSQLTemplate) {
		this.changeLogSaveLogJdbcSQLTemplate = changeLogSaveLogJdbcSQLTemplate;
	}

	public String getChangeLogLastLogJdbcSQLTemplate() {
		return changeLogLastLogJdbcSQLTemplate;
	}

	public void setChangeLogLastLogJdbcSQLTemplate(String changeLogLastLogJdbcSQLTemplate) {
		this.changeLogLastLogJdbcSQLTemplate = changeLogLastLogJdbcSQLTemplate;
	}

	public String getChangeLogLastChangeLogIdSQLTemplate() {
		return changeLogLastChangeLogIdSQLTemplate;
	}

	public void setChangeLogLastChangeLogIdSQLTemplate(String changeLogLastChangeLogIdSQLTemplate) {
		this.changeLogLastChangeLogIdSQLTemplate = changeLogLastChangeLogIdSQLTemplate;
	}

	public String getChangeLogIdEQChangeLogSQLTemplate() {
		return changeLogIdEQChangeLogSQLTemplate;
	}

	public void setChangeLogIdEQChangeLogSQLTemplate(String changeLogIdEQChangeLogSQLTemplate) {
		this.changeLogIdEQChangeLogSQLTemplate = changeLogIdEQChangeLogSQLTemplate;
	}

	public String getChangeLogIdGtChangeLogSQLTemplate() {
		return changeLogIdGtChangeLogSQLTemplate;
	}

	public void setChangeLogIdGtChangeLogSQLTemplate(String changeLogIdGtChangeLogSQLTemplate) {
		this.changeLogIdGtChangeLogSQLTemplate = changeLogIdGtChangeLogSQLTemplate;
	}

	protected ChangeLogResolver getChangeLogResolver() {
		assertInited();
		return changeLogResolver;
	}

	@Override
	protected boolean isResolveInit() {
		return super.isResolveInit() && changeLogResolver != null;
	}

	public String getChangeLogNamespace() {
		return changeLogNamespace;
	}

	public void setChangeLogNamespace(String changeLogNamespace) {
		this.changeLogNamespace = changeLogNamespace;
	}

	public String getChangeLogTableSchema() {
		return changeLogTableSchema;
	}

	public void setChangeLogTableSchema(String changeLogTableSchema) {
		this.changeLogTableSchema = changeLogTableSchema;
	}

	public String getChangeLogTableName() {
		return changeLogTableName;
	}

	public void setChangeLogTableName(String changeLogTableName) {
		this.changeLogTableName = changeLogTableName;
	}

	/**
	 * 获取ChangeLog数据描述对象
	 */
	protected DataEdgeDescriptor resolveChangeLogDataDescriptor() {
		synchronized (this) {
			if (changeLogDataDescriptor == null) {
				changeLogDataDescriptor = resolveChangeLogDataDescriptor(null);
			}
		}
		return changeLogDataDescriptor;
	}

	/**
	 * 获取ChangeLog数据描述对象
	 */
	protected DataEdgeDescriptor resolveChangeLogDataDescriptor(String dataIdentityPrefix) {
		DataEdgeDescriptor desc = null;
		if (StringUtils.hasText(dataIdentityPrefix)) {
			desc = resolveChangeLogDataDescriptor().clone();
			Class<?> descClazz = ClassUtils.getUserClass(getDescriptorClass());
			String clazzName = descClazz.getName();
			
			Method method = ClassUtils.getMethodIfAvailable(descClazz, "setDataIdentityPrefix",
					new Class<?>[] { String.class });
			Assert.notNull(method, String.format("找不到类(%s)的setDataIdentityPrefix()方法", clazzName));
			try {
				method.invoke(desc, dataIdentityPrefix);
			} catch (Throwable e) {
				throw new IllegalArgumentException(String.format("调用类(%s)的setDataIdentityPrefix()方法时出错:%s",
						clazzName, e.getMessage()), e);
			}
		} else {
			Class<?> descClazz = ClassUtils.getUserClass(getDescriptorClass());
			String clazzName = descClazz.getName();
			try {
				desc = (DataEdgeDescriptor) getDescriptorClass().newInstance();
			} catch (Throwable e) {
				throw new IllegalArgumentException(String.format("无法实例化类(%s)", clazzName));
			}
			Method method = ClassUtils.getMethodIfAvailable(descClazz, "setId", new Class<?>[] { String.class });
			Assert.notNull(method, String.format("找不到类(%s)的setId()方法", clazzName));
			try {
				method.invoke(desc, getDescriptorIdentity());
			} catch (Throwable e) {
				throw new IllegalArgumentException(String.format("调用类(%s)的setId()方法时出错:%s", clazzName, e.getMessage()),
						e);
			}
		}
		return desc;
	}

	/**
	 * 获取数据最后的变更版本
	 */
	public String getDataLastChanageVersion() {
		DataChangeLog log = getChangeLogResolver().getLastChangeLog(resolveChangeLogDataDescriptor());
		return log != null ? log.getId() : "0";
	}
	
	public String getDataLastChanageVersion(String dataIdentityPrefix) {
		DataChangeLog log = getChangeLogResolver().getLastChangeLog(resolveChangeLogDataDescriptor(dataIdentityPrefix));
		return log != null ? log.getId() : "0";
	}

	@Override
	public void initContext() {
		super.initContext();
		synchronized (this) {
			ContextJdbcDataChangeLogStorage changeLogStorage = new ContextJdbcDataChangeLogStorage();
			changeLogResolver = changeLogStorage;

			changeLogStorage.setDataSource(getResolvedDataSource());
			changeLogStorage.setNamespace(getChangeLogNamespace());
			changeLogStorage.setTableSchemaName(getChangeLogTableSchema());
			changeLogStorage.setTableName(getChangeLogTableName());
			changeLogStorage.setIdEQChangeLogSQLTemplate(getChangeLogIdEQChangeLogSQLTemplate());
			changeLogStorage.setIdGtChangeLogSQLTemplate(getChangeLogIdGtChangeLogSQLTemplate());
			changeLogStorage.setLastChangeLogIdSQLTemplate(getChangeLogLastChangeLogIdSQLTemplate());
			changeLogStorage.setLastLogJdbcSQLTemplate(getChangeLogLastLogJdbcSQLTemplate());
			changeLogStorage.setCreateStorageJdbcSQLTemplate(getChangeLogCreateStorageJdbcSQLTemplate());
			changeLogStorage.setSaveLogJdbcSQLTemplate(getChangeLogSaveLogJdbcSQLTemplate());

			try {
				changeLogStorage.afterPropertiesSet();
			} catch (Throwable e) {
				changeLogResolver = null;
				throw new IllegalArgumentException(e.getMessage(), e);
			}
			changeLogStorage.initContext();
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		Assert.notNull(getDescriptorClass());
		Assert.isAssignable(DataEdgeDescriptor.class, getDescriptorClass());
	}

	@Override
	public void finiContext() {
		super.finiContext();
		synchronized (this) {
			changeLogResolver.finiContext();
			changeLogResolver = null;
		}
	}

}
